package org.fastsyncer.framework.manager;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.fastsyncer.common.constant.ConnectorConstant;
import org.fastsyncer.common.constant.MappingConstant;
import org.fastsyncer.common.entity.DataSourceConfig;
import org.fastsyncer.common.entity.Mapping;
import org.fastsyncer.common.entity.MappingTask;
import org.fastsyncer.common.util.DateUtil;
import org.fastsyncer.manager.framework.ManagerFactory;
import org.fastsyncer.manager.store.DataCenter;
import org.fastsyncer.manager.util.ManagerUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 驱动业务操作API,包含驱动新增、修改、删除、查询、启动、停止
 * @author YangPei
 *
 */
public class Manager {

	private static Logger logger = LoggerFactory.getLogger(Manager.class);

	private static final Manager instance = new Manager();

	private Manager() {
	}

	public static Manager getInstance() {
		return instance;
	}

	private static DataCenter data = DataCenter.getInstance();

	private static ManagerFactory manager = ManagerFactory.getInstance();

	/**
	 * 新增驱动
	 * 
	 * @param mapping
	 * @throws Exception
	 */
	public String add(String mapping) throws Exception {
		JSONObject rel = new JSONObject(mapping);
		String name = (String) rel.get("name");
		if (data.getMapping(name) != null) {
			throw new Exception("驱动已存在!");
		}

		MappingTask mappingTask = ManagerUtil.parseMapping(mapping);
		boolean store = data.storeMapping(name, mappingTask);
		if (!store) {
			logger.error("新增驱动失败!");
			return "新增驱动失败!";
		}
		return "新增驱动成功!";
	}

	/**
	 * 修改驱动
	 * 
	 * @param mapping
	 * @throws Exception
	 */
	public String update(String mapping) throws Exception {
		MappingTask mappingTask = ManagerUtil.parseMapping(mapping);
		// 当前为启用
		if (!mappingTask.isEnable()) {
			throw new Exception("驱动已被禁用.");
		}
		//检查驱动是否处于运行状态
		if(this.isRun(mappingTask.getName())){
			throw new Exception("驱动正在运行.");
		}
		
		boolean store = data.storeMapping(mappingTask.getName(), mappingTask);
		if (!store) {
			logger.error("修改驱动失败!");
			throw new Exception("修改驱动失败!");
		}
		return "修改驱动成功!";
	}

	/**
	 * 禁用驱动
	 * 
	 * @param name
	 * @throws Exception
	 */
	public String enable(String name) throws Exception {
		MappingTask mappingTask = (MappingTask) data.getMapping(name);
		String result = "恢复驱动成功!";
		// 当前为启用
		if (mappingTask.isEnable()) {
			//检查驱动是否处于运行状态
			if(this.isRun(name)){
				throw new Exception("请先停止驱动或等待任务结束.");
			}
			
			// 修改状态为false,去掉启用时间
			mappingTask.setEnable(false);
			mappingTask.setStartDate(null);
			result = "禁用驱动成功!";
		} else {
			// 修改状态为true,设置最新启用时间
			mappingTask.setEnable(true);
			mappingTask.setStartDate(new Date());
		}

		boolean store = data.storeMapping(mappingTask.getName(), mappingTask);
		if (!store) {
			logger.error("修改驱动状态失败!");
			throw new Exception("修改驱动状态失败!");
		}
		return result;
	}

	/**
	 * 删除驱动
	 * 
	 * @param name
	 * @throws Exception
	 */
	public String delete(String name) throws Exception {
		MappingTask mappingTask = (MappingTask) data.getMapping(name);
		if (mappingTask.isEnable()) {
			throw new Exception("请先禁用驱动!");
		}
		// 移除正在运行的任务
		ManagerFactory.removeRunning(name);
		ManagerFactory.removeQueue(name);
		boolean remove = data.remove(mappingTask.getName());
		if (!remove) {
			logger.error("删除驱动失败!");
			throw new Exception("删除驱动失败!");
		}
		return "删除驱动成功!";
	}

	/**
	 * 启动驱动
	 * 
	 * @param mapping
	 * @throws Exception
	 */
	public String start(String name) throws Exception {
		MappingTask mappingTask = (MappingTask) data.getMapping(name);
		
		// 1、运行模式
		String model = mappingTask.getModel();
		if(!MappingConstant.SYNC_ALL.equals(model)){
			throw new IllegalArgumentException("只有数据迁移模式才能启动！");
		}
		
		// 2、检查是否启用
		if (!mappingTask.isEnable()) {
			throw new IllegalArgumentException("驱动状态必须为启用！");
		}

		// 3、检查同步属性、主键
		this.validateSyncFields(mappingTask);

		// 4、校验同步任务是否正在处理中
		manager.validateTask(name);

		// 5、如果上一次的任务已经执行完成，则还原同步默认值
		if (mappingTask.getProcess() == mappingTask.getProcessCompleted()) {
			mappingTask.setSuccess(0);
			mappingTask.setFail(0);
			mappingTask.setError(0);
			mappingTask.setProcessCompleted(0);
			mappingTask.setRunTime(0L);
		}
		logger.info("正在提交同步任务.");
		manager.handle(mappingTask);
		return "驱动启动成功！";
	}
	
	/**
	 * 停止驱动
	 * 
	 * @param mapping
	 * @throws Exception
	 */
	public String stop(String name) throws Exception {
		logger.info("正在停止驱动任务.");
		MappingTask mappingTask = (MappingTask) data.getMapping(name);
		// 1、检查是否启用
		if (!mappingTask.isEnable()) {
			throw new IllegalArgumentException("驱动状态必须为启用！");
		}
		// 2、移除正在处理的同步任务
		boolean removeRunning = ManagerFactory.removeRunning(name);
		boolean removeQueue = ManagerFactory.removeQueue(name);
		String res = removeRunning || removeQueue ? "停止驱动成功！" : "没有驱动可以停止！";
		return res;
	}

	/**
	 * 获取驱动
	 * @param dirverName
	 * @return
	 * @throws Exception
	 */
	public Object getDriver(String dirverName) throws Exception {
		return data.getMapping(dirverName);
	}

	/**
	 * 获取所有驱动
	 * @return
	 * @throws Exception
	 */
	public List<Object> getDriverAll() throws Exception {
		List<Object> list = data.getMappingAll();
		for (Object object : list) {
			MappingTask task = (MappingTask) object;

			Date startDate = task.getStartDate();
			task.setStartDateStr("0天0小时0分0秒");
			if (startDate != null) {
				// 获取时间差
				task.setStartDateStr(DateUtil.getDiff(startDate, new Date()));
			}
			
			// 获取运行状态
			boolean run = isRun(task.getName());
			task.setRun(run);
		}
		return list;
	}

	/**
	 * 获取驱动同步日志
	 * 
	 * @param name
	 * @throws Exception
	 */
	public File getMappingLog(String name) {
		return data.getMappingLog(name);
	}

	/**
	 * 获取正在排队的同步任务
	 * 
	 * @return
	 */
	public List<String> getQueue() {
		List<String> list = new ArrayList<String>();
		ConcurrentLinkedQueue<String> queue = ManagerFactory.getQueue();
		for (String t : queue) {
			list.add(t);
		}
		return list;
	}

	/**
	 * 获取正在运行的同步任务
	 * 
	 * @return
	 */
	public List<String> getRunning() {
		List<String> list = new ArrayList<String>();
		ConcurrentHashMap<String, String> running = ManagerFactory.getRunning();
		for (Map.Entry<String, String> entry : running.entrySet()) {
			list.add(entry.getKey());
		}
		return list;
	}
	
	/**
	 * 
	 * 查询是否在运行
	 * @param name 驱动名称
	 * @return true:正在运行，否则false
	 */
	public boolean isRun(String name) {
		//判断是否在排队
		ConcurrentLinkedQueue<String> queue = ManagerFactory.getQueue();
		if(queue.contains(name)){
			return true;
		}
		//判断是否在运行
		ConcurrentHashMap<String, String> running = ManagerFactory.getRunning();
		return running.get(name)!=null;
	}
	
	/**
	 * 检查同步属性、主键
	 * @param mappingTask
	 * @throws IllegalArgumentException
	 */
	private void validateSyncFields(MappingTask mappingTask) throws IllegalArgumentException {
		Mapping sourceMapping = mappingTask.getSourceMapping();
		List<HashMap<String, Object>> sourceFileds = sourceMapping.getFileds();
		if (sourceFileds == null || sourceFileds.size() < 1) {
			throw new IllegalArgumentException("缺少基本信息!");
		}
		
		// 数据源连接器类型
		String sourceConn = sourceMapping.getConnector();
		// 目标源驱动集合
		List<Mapping> targetMappings = mappingTask.getMappings();
		for (Mapping map : targetMappings) {
			List<HashMap<String, Object>> fileds = map.getFileds();
			if (fileds == null || fileds.size() < 1) {
				throw new IllegalArgumentException("缺少基本信息!");
			}

			// 如果都是数据库连接器类型
			if (ConnectorConstant.DB_CONNECTOR.equals(sourceConn) && sourceConn.equals(map.getConnector())) {
				DataSourceConfig sourceConfig = (DataSourceConfig) sourceMapping.getConfig();
				DataSourceConfig targetConfig = (DataSourceConfig) map.getConfig();
				String sKey = sourceConfig.getPrimaryKey();
				String tKey = targetConfig.getPrimaryKey();

				// 检查数据源主键是否存在
				boolean isExistSourcePK = false;
				for (HashMap<String, Object> source : sourceFileds) {
					String sName = (String) source.get("name");
					if (sKey.equals(sName)) {
						isExistSourcePK = true;
						break;
					}
				}
				if (!isExistSourcePK) {
					throw new IllegalArgumentException("基本信息数据源缺少主键!");
				}
				// 检查目标源主键是否存在
				boolean isExistTargetPK = false;
				for (HashMap<String, Object> source : fileds) {
					String tName = (String) source.get("name");
					if (tKey.equals(tName)) {
						isExistTargetPK = true;
						break;
					}
				}
				if (!isExistTargetPK) {
					throw new IllegalArgumentException("基本信息目标源缺少主键!");
				}
			}
		}
		// END
	}

}
